package com.hundsun.openservice.sdk;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

import java.io.IOException;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.hundsun.openservice.sdk.bean.ParameterBean;

public class ParamParser {

    private ParamParser() {

    }

    public static JSONObject parseParas(ParameterBean paramBean) throws Exception {
        JSONObject argJson = new JSONObject();
        JSONObject queryJson = new JSONObject();
        JSONArray queryArrayMust = null;
        JSONArray queryArrayMustNot = null;
        JSONObject aggregations = new JSONObject(); // 最外一层json，只有aggregations属性的
        JSONObject reqAggrJson = new JSONObject(); // 聚合真正开始部分，命名定为request
        JSONObject termsAggrJson = null;
        JSONObject dateHistgam = null;
        JSONObject queryStrJson = null;
        String[] fields = paramBean.getStatFields();
        Map mertrics = paramBean.getMetrics();
        Map paramMust = paramBean.getParaMapMust();
        Map paramMustNot = paramBean.getParaMapMustNot();
        boolean dateHist = paramBean.isDateHist();
        String dateHistType = paramBean.getDateHistType();
        // must查询语句组装
        if (paramMust != null && paramMust.size() > 0) {
            queryArrayMust = new JSONArray();
            queryArrayMust = buildQuery(queryArrayMust, paramMust);
        }

        if (StringUtils.isNotEmpty(paramBean.getQueryStr())) {
            if (queryArrayMust == null) {
                queryArrayMust = new JSONArray();
            }
            queryStrJson = buildQueryStr(paramBean.getQueryStr());
            queryArrayMust.add(queryStrJson);
        }

        // must_not查询语句组装
        if (paramMustNot != null && paramMustNot.size() > 0) {
            queryArrayMustNot = new JSONArray();
            queryArrayMustNot = buildQuery(queryArrayMustNot, paramMustNot);
        }

        // 查询条件合并

        if (queryArrayMust != null || queryArrayMustNot != null) {
            XContentBuilder xContentBuilder = null;
            xContentBuilder = jsonBuilder().startObject().field("bool");
            xContentBuilder.startObject();
            if (queryArrayMust != null) {
                xContentBuilder.field("must", queryArrayMust);
            }
            if (queryArrayMustNot != null) {
                xContentBuilder.field("must_not", queryArrayMustNot);
            }
            xContentBuilder.endObject().endObject();
            queryJson = JSONObject.parseObject(xContentBuilder.string());
            argJson.put("query", queryJson);
        }

        // 设置分页，默认从0开始，查询10条
        argJson.put("from", paramBean.getFrom());
        argJson.put("size", paramBean.getSize());

        // 时间聚合
        if (dateHist) {
            dateHistgam = buildDateHistgram(dateHistType, paramBean.getDateFieldName());

        }
        // 开始组装request
        if (fields != null && fields.length > 0) {
            termsAggrJson = buildTermsAggr(0, fields, mertrics);
        }
        if (dateHistgam != null) {
            aggregations.put("time", reqAggrJson); // 时间聚合命名为time，方便结果解析
            reqAggrJson.put("date_histogram", dateHistgam);// 按时间分割聚合，名称要严格与es的api对应
            if (termsAggrJson != null) {
                reqAggrJson.put("aggregations", termsAggrJson);
            }
            argJson.put("aggregations", aggregations);
        } else {
            if (termsAggrJson != null) {
                argJson.put("aggregations", termsAggrJson);
            }
        }

        return argJson;
    }

    private static JSONObject buildNumericAggr(Map<String, String> mertrics) {
        JSONObject aggrJson = new JSONObject();
        JSONObject numericAggr = null;
        JSONObject fieldJson = null;
        // 组装统计类型聚合
        if (mertrics == null || mertrics.size() == 0) {

            return null;
        }
        for (Map.Entry<String, String> mertric : mertrics.entrySet()) {
            fieldJson = new JSONObject();
            numericAggr = new JSONObject();
            String numericType = mertric.getKey();
            String numericField = mertric.getValue();
            fieldJson.put("field", numericField);
            numericAggr.put(numericType, fieldJson);
            fieldJson.put("format", "##########0.00");
            aggrJson.put("numeric_" + numericType + "_" + numericField, numericAggr);
        }

        return aggrJson;
    }

    // 多层terms处理
    private static JSONObject buildTermsAggr(int i, String[] fields, Map mertrics) {
        JSONObject aggrJson = new JSONObject();
        JSONObject termsJson = new JSONObject();
        JSONObject fieldJson = new JSONObject();
        fieldJson.put("field", fields[i]);
        fieldJson.put("size", 0);
        termsJson.put("terms", fieldJson);
        if (fields.length > i + 1) {
            termsJson.put("aggregations", buildTermsAggr(i + 1, fields, mertrics));
        } else {
            termsJson.put("aggregations", buildNumericAggr(mertrics));
        }
        aggrJson.put(fields[i], termsJson);
        return aggrJson;
    }

    private static JSONObject buildQueryStr(String queryStr) throws IOException {
        JSONObject queryStrJson = null;
        XContentBuilder xContentBuilder = null;
        if (StringUtils.isEmpty(queryStr)) {
            return null;
        }
        xContentBuilder = jsonBuilder().startObject().field("query_string").startObject().field("query", queryStr)
                .endObject().endObject();
        queryStrJson = JSONObject.parseObject(xContentBuilder.string());
        return queryStrJson;

    }

    private static JSONArray buildQuery(JSONArray queryArray, Map<String, String[]> params) throws IOException {
        XContentBuilder xContentBuilder = null;
        if (params != null && params.size() > 0) {
            for (Map.Entry<String, String[]> queryField : params.entrySet()) {
                String field = queryField.getKey();
                String[] values = queryField.getValue();
                switch (values.length) {
                case 1:
                    xContentBuilder = jsonBuilder().startObject().field("term").startObject().field(field).startObject()
                            .field("value", values[0]).endObject().endObject().endObject();
                    break;

                case 2:
                    if (StringUtils.endsWithIgnoreCase(values[0], "lt")) {
                        xContentBuilder = XContentFactory.jsonBuilder().startObject().field("range").startObject()
                                .field(field).startObject().field("lt", values[1]).endObject().endObject().endObject();
                    } else if (StringUtils.endsWithIgnoreCase(values[0], "lte")) {
                        xContentBuilder = XContentFactory.jsonBuilder().startObject().field("range").startObject()
                                .field(field).startObject().field("lte", values[1]).endObject().endObject().endObject();
                    } else if (StringUtils.endsWithIgnoreCase(values[0], "gt")) {
                        xContentBuilder = XContentFactory.jsonBuilder().startObject().field("range").startObject()
                                .field(field).startObject().field("gt", values[1]).endObject().endObject().endObject();
                    } else if (StringUtils.endsWithIgnoreCase(values[0], "gte")) {
                        xContentBuilder = XContentFactory.jsonBuilder().startObject().field("range").startObject()
                                .field(field).startObject().field("gte", values[1]).endObject().endObject().endObject();
                    } else {
                        xContentBuilder = XContentFactory.jsonBuilder().startObject().field("terms").startObject()
                                .field(field, values).endObject().endObject();
                    }
                    break;
                case 3:
                    if (StringUtils.endsWithIgnoreCase(values[1], "to")) {
                        xContentBuilder = jsonBuilder().startObject().field("range").startObject().field(field)
                                .startObject().field("from", values[0]).field("to", values[2]).endObject().endObject()
                                .endObject();
                    } else {
                        xContentBuilder = jsonBuilder().startObject().field("terms").startObject().field(field, values)
                                .endObject().endObject();
                    }

                    break;
                default:
                    xContentBuilder = jsonBuilder().startObject().field("terms").startObject().field(field, values)
                            .endObject().endObject();
                    break;
                }

                queryArray.add(JSONObject.parse(xContentBuilder.string()));

            }
        }
        return queryArray;
    }

    private static JSONObject buildDateHistgram(String type, String dateFieldName) {
        JSONObject dateHistgram = new JSONObject();
        dateHistgram.put("field", dateFieldName);
        dateHistgram.put("interval", type);
        dateHistgram.put("time_zone", "+08:00");
        return dateHistgram;
    }

}
